/*
 * Model.java
 *
 * Created on 3 November, 2010, 5:14 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package icardex;

import java.awt.Dimension;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import jxl.*;
import jxl.read.biff.BiffException;

/**
 * This is the main class which does all the processing part.
 * Data is provided from the controller.
 * @author Bageshwar
 */
public class Model {

    Dimension cardDim, pageDim, matrix;
    String inputHTML = "";
    String inputXLS = "";
    String outputHTML = "";
    StringBuffer card;
    String dimensionUnit = "pt";

    //1pt = these many mm . The input is expected in mm 
    float convert = 2.8346456693f;
    /**
     * The map contains the map between the fields in the html file and
     * the fields in the xls file.
     */
    HashMap<String, String> map;
    ArrayList<String> htmlFields;
    ArrayList<String> xlsFields;

    /** Creates a new instance of Model */
    public Model() {
        //map  = new HashMap<String,String>();
        //xlsFields = new ArrayList<String>();
    }

    public void setInputHTMLFile(String filename) {
        inputHTML = filename;
    }

    public void setInputXLSFile(String xls) {
        inputXLS = xls;
    }

    public void setMap(HashMap<String, String> m) {
        map = m;
    }

    /**
     * Reads the html file and returns the discovered fields.
     */
    public ArrayList<String> getFieldNamesInHTML() throws IOException {
        //calculate the fields in the html file.

        //GET Input stream
        FileInputStream fin = new FileInputStream(inputHTML);

        byte[] data = new byte[1024]; //1kb block
        card = new StringBuffer();

        htmlFields = new ArrayList<String>();
        int c = 0;
        c = (fin.read());
        while (c != -1) {

            //htmlFields.add();
            card.append((char) c);
            c = fin.read();
        }
        //data has been read into the string buffer .. data is HTML Code
        //System.out.println(sb);
        //arraylist is initialized which will contain the list of fields present in the html file.


        //now check the the occurance of a $ and then parse the string between the 2 consecutive {}

//        int i = 0;
//        String s = "";
//        StringTokenizer stk = new StringTokenizer(card.toString(), "$[");
//        System.out.println(stk.countTokens());
//        stk.nextToken(); //the first token is useless
//
//        while (stk.hasMoreTokens()) {
//
//            s = stk.nextToken();
//            System.out.println("extracted token " + s);
//            i = s.indexOf("]$");
//            s = s.substring(1, i);
//
//            htmlFields.add(s);
//        }

        htmlFields = myTokenizer(card.toString());
        return htmlFields;
    }

    private ArrayList<String> myTokenizer(String s) {
        ArrayList<String> list = new ArrayList<String>();
        int fromIndex = 0, index = 0;


        index = s.indexOf("$[", fromIndex);
        while (index != -1) {

            int t = s.indexOf("]$", index);
            String str = s.substring(index + 2, t);
            //System.out.println(str);
            fromIndex = index + 2;
            index = s.indexOf("$[", fromIndex);

            list.add(str);
        }
        System.out.println(list);
        return list;
    }

    /**
     * Reads the Excel file and returns the discovered fields.
     */
    public ArrayList<String> getFieldNamesInXLS() throws IOException, BiffException {
        loadXLSData();
        return xlsFields;
    }

    private void loadXLSData() throws IOException, BiffException {
        xlsFields = new ArrayList<String>();
        Workbook workbook = Workbook.getWorkbook(new File(inputXLS));
        Sheet sheets[] = workbook.getSheets();
        Sheet sheet = sheets[0];
        Cell cells[] = sheet.getRow(0);
        for (int i = 0; i < cells.length; i++) {
            xlsFields.add(cells[i].getContents());

        }
        workbook.close();
    }

    /**
     *Takes the width and height of id card in mm
     */
    public void setCardDimensions(Dimension d) {
        cardDim = d;
    }

    /**
     *Takes the width and height of page in mm
     */
    public void setPageDimensions(Dimension d) {
        pageDim = d;
    }

    /**
     * Takes a width and height , which is the actual matrix representation
     * of how each ICard will be arranged on the page.
     * The user should verify the settings, they would not be checked here.
     */
    public void setMatrix(Dimension d) {
        matrix = d;
    }

    public void setDestinationFile(String dFile) {
        outputHTML = dFile;
    }

    /**
     * Does all the processing. First maps the field to columns,
     * then opens the Excel file , and reads one row at a time,
     * replacing the fields with the column values.
     * At the end of the loop, the resulting text
     * is appended to a StringBuffer, and after all the
     * rows have been traversed, the resulting StringBuffer is
     * flushed into the output file.
     */
    public void make() throws IOException, BiffException {


        //extracting data inside the body tag to be given to make();
        String template = extractTemplate();


        //need a mechanism to know which col mapped to which field
        HashMap<String, Integer> indexMap = new HashMap<String, Integer>();
        //map.values will give a list of column names.
        for (Iterator<String> it = (new ArrayList<String>(map.keySet())).iterator(); it.hasNext();) {
            String key = it.next();
            indexMap.put(key, this.xlsFields.indexOf(map.get(key)));

        }

        //System.out.println(map);
        //System.out.println(indexMap);


        Workbook workbook = Workbook.getWorkbook(new File(inputXLS));
        Sheet sheets[] = workbook.getSheets();
        Sheet sheet = sheets[0];
        StringBuffer fin = new StringBuffer();
        String temp;
        //String withoutRN = card.toString().replaceAll("\r\n","");
        int len = sheet.getRows();
        for (int j = 1; j < len; j += matrix.getWidth()) {
            StringBuffer divs = new StringBuffer();
            divs.append("<table class='row'><tr>");
            for (int k = 0; k < matrix.getWidth() && (j + k) < len; k++) {
                Cell cells[] = sheet.getRow(j + k);
                temp = template;
                //processing 1 row
                divs.append("<td class='column'>");
                for (Iterator<String> it = htmlFields.iterator(); it.hasNext();) {
                    String key = it.next();
                    String value = cells[indexMap.get(key)].getContents();
                    //System.out.println(key+"-->"+value);
                    temp = temp.replaceAll("\\$\\[" + key + "\\]\\$", value);
                    //System.out.print(temp);
                }
                divs.append(temp);
                divs.append("</td>");
            }
            divs.append("</tr></table>");
            fin.append(divs);
            //System.out.println("Temp : - "+temp);

        }

        workbook.close();
        //System.out.println(fin.toString());

        String start = "";// "<html><head><title>Created with ICardex</title></head><body>";
        int i = card.indexOf("<body");
        start = card.substring(0, i);
        String end = "</body></html>";

        FileOutputStream fout = new FileOutputStream(outputHTML);
        fout.write(start.getBytes());
        fout.write(doDimensionStyling());  //adds the <style> tag and appropriate id and rules
        fout.write(fin.toString().getBytes());
        fout.write(end.getBytes());
        fout.close();
    }

    private String extractTemplate() {
        String s = card.toString();
        int i = card.indexOf("<body");
        int t = card.indexOf("<", i + 1);
        int j = card.lastIndexOf("</body>");
        s = s.substring(t, j);
        //System.out.println(s);
        return s;
    }

    /**
     * Returns the <Style> tag with the appropriate dimensions
     * in mm.
     */
    private byte[] doDimensionStyling() {
        String style = "<style type=\"text/css\">"
                + "overflow: hidden;"
                + " .row {"
                + "width: " + ((cardDim.getWidth() * matrix.getWidth() + 10) * convert) + dimensionUnit + ";"
                + "height: " + (cardDim.getHeight() * convert) + dimensionUnit + ";"
                + "}"
                + " .column {"
                + "width: " + (cardDim.getWidth() * convert) + dimensionUnit + ";"
                + "height: " + (cardDim.getHeight() * convert) + dimensionUnit + ";"
                + "}"
                + "</style>";
        return style.getBytes();
    }

    /**
     * Checks the card dimensions, the matrix against the page dimensions
     * and tells if its correct or not.
     */
    public boolean checkDimensions() {

        int w = (int) (cardDim.getWidth() * matrix.getWidth()) + 10;
        //need to implement a complicated algorithm 
        //to determine if the height is valid.
        if (w > pageDim.getWidth()) {
            return false;
        } else {
            return true;
        }
    }

    /*
     *
     * This method clears all the fields. ie. Arraylists and maps
     *
     */
    public void clear() {

        try {
            this.htmlFields.clear();
        } catch (NullPointerException e) {
            //do nothing
        }
        try {
            this.map = new HashMap<String, String>();
        } catch (NullPointerException e) {
            //do nothing
        }

        try {
            this.xlsFields.clear();
        } catch (NullPointerException e) {
            //do nothing
        }



    }
}
